home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et-2_2.lha / et2.2 / src / CollView.C < prev    next >
C/C++ Source or Header  |  1990-12-04  |  10KB  |  481 lines

  1. //$CellSelector,CollectionView$
  2. #include "CollView.h"
  3. #include "Menu.h"
  4. #include "String.h"
  5. #include "Collection.h"
  6. #include "VObject.h"
  7. #include "CmdNo.h"
  8. #include "Error.h"
  9. #include "Math.h"
  10.  
  11. //---- CollectionView ----------------------------------------------------------
  12.  
  13. MetaImpl(CollectionView, (TP(coll), T(selection), T(gap), T(minExtent),
  14.                 T(rows), T(cols), TP(defaultItem), TP(menu), 0));
  15.  
  16. CollectionView::CollectionView(EvtHandler *eh, Collection *m, CollViewOptions o,
  17.                         int r, int c) : View(eh, gRect0)
  18. {
  19.     SetFlag(o);
  20.     defaultItem= new VObject();
  21.     rows= r;
  22.     cols= c;
  23.     SetCollection(m);
  24. }
  25.  
  26. CollectionView::~CollectionView()
  27. {
  28.     if (coll) {
  29.     coll->RemoveObserver(this);
  30.     coll->FreeAll();
  31.     SafeDelete(coll);
  32.     }
  33.     SafeDelete(xPos);
  34.     SafeDelete(yPos);
  35.     SafeDelete(defaultItem);
  36. }
  37.  
  38. //---- init methods
  39.  
  40. int CollectionView::SetSelection(Rectangle newsel)
  41. {
  42.     if (selection != newsel) {
  43.     if (IsOpen()) {
  44.         InvalidateRect(ItemRect(selection));
  45.         InvalidateRect(ItemRect(newsel));
  46.     }
  47.     selection= newsel;
  48.     if (selection.IsEmpty())
  49.         return 0;   // no selection
  50.     return 1;       // selection changed
  51.     }
  52.     return 2;           // no change
  53. }
  54.  
  55. void CollectionView::SetCollection(class Collection* m, bool freeold)
  56. {
  57.     if (coll)
  58.     coll->RemoveObserver(this);
  59.     if (freeold && coll) {
  60.     coll->FreeAll();
  61.     delete coll;
  62.     }
  63.     if (coll= m) {
  64.     coll->AssertClass(VObject);
  65.     coll->AddObserver(this);
  66.     }
  67.     selection= gRect0;
  68.     Modified();
  69.     Scroll(cPartScrollAbs, gPoint0, FALSE);
  70. }
  71.  
  72. void CollectionView::SetDefaultItem(class VObject *d)
  73.     if (defaultItem)
  74.     delete defaultItem;
  75.     defaultItem= d; 
  76. }
  77.  
  78. void CollectionView::SetMinExtent(Point e)
  79. {
  80.     if (minExtent != e) {
  81.     minExtent= e;
  82.     Modified();
  83.     }
  84. }
  85.  
  86. Metric CollectionView::GetMinSize()
  87. {
  88.     Update();
  89.     return GetExtent();
  90. }
  91.  
  92. //---- layout
  93.  
  94. void CollectionView::ConstrainScroll(Point *p)
  95. {
  96.     bool outside;
  97.     Point pp= PointToItem(*p, &outside);
  98.     if (! outside)
  99.     p->y= ItemRect(0, pp.y).origin.y;
  100. }
  101.  
  102. void CollectionView::SetOrigin(Point at)
  103. {
  104.     register int x, y;
  105.     
  106.     View::SetOrigin(at);
  107.     at+= gap;
  108.     for (x= 0; x < cols; x++)
  109.     for (y= 0; y < rows; y++)
  110.         GetItem(x, y)->SetOrigin(Point(xPos[x]+at.x, yPos[y]+at.y));
  111. }
  112.  
  113. void CollectionView::Update()
  114. {
  115.     register VObject *gop;
  116.     register int x, y, ww, hh, w, h;
  117.     int xpos= 0, ypos= 0, sz;
  118.     Rectangle r;
  119.     Point g;
  120.  
  121.     if (!TestFlag(eCVModified))
  122.     return;
  123.     ResetFlag(eCVModified);
  124.     if (coll == 0) {
  125.     ForceRedraw();
  126.     return;
  127.     }
  128.     sz= coll->Size();
  129.     if (rows <= 0)
  130.     SetFlag(eCVExpandRows);
  131.     if (cols <= 0)
  132.     SetFlag(eCVExpandCols);
  133.     
  134.     if (TestFlag(eCVExpandRows) && TestFlag(eCVExpandCols)) {
  135.     cols= intsqrt(sz);
  136.     rows= (sz+cols-1) / cols;
  137.     } else if (TestFlag(eCVExpandRows))
  138.     rows= (sz+cols-1) / cols;
  139.     else if (TestFlag(eCVExpandCols))
  140.     cols= (sz+rows-1) / rows;
  141.  
  142.     yPos= (short*) Realloc(yPos, (rows+1) * sizeof(short));
  143.     xPos= (short*) Realloc(xPos, (cols+1) * sizeof(short));
  144.  
  145.     xpos= ypos= 0;
  146.     g= 2*gap;
  147.     if (TestFlag(eCVGrid))
  148.     g+= gPoint1;
  149.     
  150.     for (x= 0; x < cols; x++) {
  151.     xPos[x]= xpos;
  152.     ww= minExtent.x;
  153.     for (y= 0; y < rows; y++) {
  154.         gop= GetItem(x, y);
  155.         gop->SetContainer(this);
  156.         gop->CalcExtent();
  157.         w= gop->Width();
  158.         ww= max(ww, w);
  159.     }
  160.     xpos+= ww+g.x;
  161.     }
  162.     xPos[x]= xpos;
  163.  
  164.     for (y= 0; y < rows; y++) {
  165.     yPos[y]= ypos;
  166.     hh= minExtent.y;
  167.     for (x= 0; x < cols; x++) {
  168.         h= GetItem(x, y)->Height();
  169.         hh= max(hh, h);
  170.     }
  171.     ypos+= hh+g.y;
  172.     }
  173.     yPos[y]= ypos;
  174.  
  175.     for (x= 0; x < cols; x++)
  176.     for (y= 0; y < rows; y++)
  177.         GetItem(x, y)->SetContentRect(ItemRect(x, y).Inset(gap), FALSE);
  178.  
  179.     if (TestFlag(eCVGrid)) {
  180.     xpos--;
  181.     ypos--;
  182.     }
  183.     SetExtent(Point(xpos, ypos));
  184.     ForceRedraw();
  185. }
  186.  
  187. //---- update
  188.  
  189. void CollectionView::DoObserve(int, int, void *, Object *op)
  190. {
  191.     if (op == coll)
  192.     Modified();
  193. }
  194.  
  195. void CollectionView::Modified()
  196. {
  197.     SetFlag(eCVModified);
  198.     if (IsOpen())
  199.     Update();
  200. }
  201.  
  202. //---- mapping
  203.  
  204. Point CollectionView::PointToItem(Point p, bool *outside)
  205. {
  206.     register int x, y;
  207.     register bool out= FALSE;
  208.  
  209.     if (coll == 0 || coll->Size() <= 0) {
  210.     if (outside)
  211.         *outside= TRUE;
  212.     return gPoint0;
  213.     }
  214.     p-= GetOrigin();
  215.     if (p.x < xPos[0]) {
  216.     out= TRUE;
  217.     x= 0;
  218.     } else if (p.x >= xPos[cols]) {
  219.     out= TRUE;
  220.     x= cols-1;
  221.     } else {
  222.     for (x= 0; x < cols; x++)
  223.         if (p.x >= xPos[x] && p.x < xPos[x+1])
  224.         break;
  225.     }
  226.     if (p.y < yPos[0]) {
  227.     out= TRUE;
  228.     y= 0;
  229.     } else if (p.y >= yPos[rows]) {
  230.     out= TRUE;
  231.     y= rows-1;
  232.     } else {
  233.     for (y= 0; y < rows; y++)
  234.         if (p.y >= yPos[y] && p.y < yPos[y+1])
  235.         break;
  236.     }
  237.     if (outside)
  238.     *outside= out;
  239.     return Point(x, y);
  240. }
  241.  
  242. Rectangle CollectionView::ItemRect(Rectangle r)
  243. {
  244.     Rectangle rr;
  245.  
  246.     if (r.IsEmpty())
  247.     return gRect0;
  248.     Update();
  249.     rr.origin.x= xPos[r.origin.x];
  250.     rr.origin.y= yPos[r.origin.y];
  251.     rr.extent.x= xPos[r.origin.x+r.extent.x] - rr.origin.x;
  252.     rr.extent.y= yPos[r.origin.y+r.extent.y] - rr.origin.y;
  253.     if (TestFlag(eCVGrid))
  254.     rr.extent-= gPoint1;
  255.     return rr+GetOrigin();
  256. }
  257.  
  258. Point CollectionView::ItemPos(VObjPtr g)
  259. {
  260.     VObjPtr gop;
  261.     Iter next(coll);
  262.  
  263.     Update();
  264.     for (int i= 0; gop= (VObject*) next(); i++)
  265.     if (gop == g)
  266.         break;
  267.     if (i >= coll->Size())
  268.     return gPoint_1;
  269.     return Point(i/rows, i%rows);
  270. }
  271.  
  272. Rectangle CollectionView::ItemRect(int x, int y)
  273. {
  274.     x= range(0, cols, x);
  275.     y= range(0, rows, y);
  276.     Rectangle r(xPos[x], yPos[y], xPos[x+1]-xPos[x], yPos[y+1]-yPos[y]);
  277.     if (TestFlag(eCVGrid))
  278.     r.extent-= gPoint1;
  279.     r.origin+= GetOrigin();
  280.     return r;
  281. }
  282.  
  283. VObject *CollectionView::GetItem(int x, int y)
  284. {
  285.     VObject *gop= 0;
  286.     int ix= x*rows+y;
  287.     
  288.     if (ix >= 0 && ix < coll->Size())
  289.     gop= (VObject*)coll->At(x*rows+y);
  290.     return gop ? gop : defaultItem;
  291. }
  292.  
  293. //---- menus
  294.  
  295. Menu *CollectionView::GetMenu()
  296. {
  297.     if (menu)
  298.     return menu;
  299.     return View::GetMenu();
  300. }
  301.  
  302. void CollectionView::DoCreateMenu(Menu *m)
  303. {
  304.     if (menu == 0)
  305.     View::DoCreateMenu(m);
  306. }
  307.  
  308. //---- event handlung
  309.  
  310. Command *CollectionView::DoLeftButtonDownCommand(Point lp, Token t, int clicks)
  311. {
  312.     if (coll && coll->Size() > 0)
  313.     return new CellSelector(this, clicks);
  314.     return View::DoLeftButtonDownCommand(lp, t, clicks);
  315. }
  316.  
  317. Command *CollectionView::DoKeyCommand(int ch, Point, Token)
  318. {
  319.     register VObject *gop= 0;
  320.     register int i;
  321.     int start= 0;
  322.     Rectangle r= GetViewedRect();
  323.     
  324.     if (r.IsNotEmpty()) {
  325.     start= r.origin.y+r.extent.y;
  326.     if (start <= GetExtent().y)
  327.         start= PointToItem(Point(0,start)).y;
  328.     }
  329.  
  330.     for (i= 0; i < rows; i++) {
  331.     gop= GetItem(0, (start+i) % rows);
  332.     if (gop && (sortmap[gop->AsString()[0]] == sortmap[ch]))
  333.         break;
  334.     }
  335.  
  336.     if (gop)
  337.     RevealAlign(ItemRect(Rectangle(ItemPos(gop), gPoint1)));
  338.     return gNoChanges;
  339. }
  340.  
  341. void CollectionView::DoOnItem(int m, VObject *vp, Point p)
  342. {
  343.     if (vp)
  344.     vp->DoOnItem(m, 0, p);
  345. }
  346.  
  347. void CollectionView::DoSelect2(Rectangle, int clickCount)
  348. {
  349.     if (GetSelection().IsNotEmpty())
  350.     DoSelect(GetSelection(), clickCount);
  351. }
  352.  
  353. void CollectionView::DoSelect(Rectangle r, int clicks)
  354. {
  355.     if (r.IsNotEmpty()) {
  356.     int partcode= clicks >= 2 ? cPartCollDoubleSelect: cPartCollSelect;
  357.     Control(GetId(), partcode, (void*) r.origin.y);
  358.     if (TestFlag(eCVClearSelection))
  359.         SetNoSelection();
  360.     }
  361. }
  362.  
  363. //---- drawing
  364.  
  365. void CollectionView::Draw(Rectangle r)
  366. {
  367.     register int x, y;
  368.     register VObject *gop;
  369.     Point p1, p2;
  370.  
  371.     if (coll == 0 || coll->Size() <= 0)
  372.     return;
  373.     p1= PointToItem(r.NW());
  374.     p2= PointToItem(r.SE()+gPoint1);
  375.     int i= 0;
  376.     for (x= p1.x; x <= p2.x; x++) {
  377.     for (y= p1.y; y <= p2.y; y++) {
  378.         i++;
  379.         gop= GetItem(x, y);
  380.         gop->DrawAll(gop->contentRect,
  381.             selection.ContainsPoint(Point(x, y)) && gop->Enabled());
  382.     }
  383.     }
  384.     if (TestFlag(eCVGrid)) {
  385.     GrSetPenNormal();
  386.     DrawGrid(p1, p2);
  387.     }
  388. }
  389.  
  390. void CollectionView::DrawGrid(Point p1, Point p2)
  391. {
  392.     register int x, y;
  393.     int xx= 0, yy= 0;
  394.     Point o= GetOrigin();
  395.  
  396.     if (p2.x >= cols-1)
  397.     xx= 1;
  398.     if (p2.y >= rows-1)
  399.     yy= 1;
  400.     for (x= p1.x; x <= p2.x-xx; x++)
  401.     GrLine(Point(xPos[x+1]-1, yPos[p1.y])+o, Point(xPos[x+1]-1, yPos[p2.y+1]-1)+o);
  402.     for (y= p1.y; y <= p2.y-yy; y++)
  403.     GrLine(Point(xPos[p1.x], yPos[y+1]-1)+o, Point(xPos[p2.x+1]-1, yPos[y+1]-1)+o);
  404. }
  405.  
  406. //---- input/output
  407.  
  408. ostream& CollectionView::PrintOn(ostream &s)
  409. {
  410.     Object::PrintOn(s);
  411.     return s << gap SP << minExtent SP << rows SP << cols SP << defaultItem SP << coll SP;
  412. }
  413.  
  414. bool CollectionView::PrintOnWhenObserved(Object *from)
  415. {
  416.     return from != coll;
  417. }
  418.  
  419. istream& CollectionView::ReadFrom(istream &s)
  420. {
  421.     Collection *m;
  422.     VObject *di;
  423.  
  424.     Object::ReadFrom(s);
  425.     s >> gap >> minExtent >> rows >> cols >> di >> m;
  426.     SetCollection(m);
  427.     SetDefaultItem(di);
  428.     return s;
  429. }
  430.  
  431. void CollectionView::Parts(Collection* col)
  432. {
  433.     View::Parts(col);
  434.     if (coll && coll->Size() < 12) // hack
  435.     col->Add(coll);
  436. }
  437.  
  438. //---- CellSelector ------------------------------------------------------------
  439.  
  440. CellSelector::CellSelector(CollectionView* v, int clicks)
  441.     SetFlag(eCmdNoReplFeedback);
  442.     lvp= v;
  443.     clickCount= clicks;
  444. }
  445.  
  446. void CellSelector::TrackFeedback(Point, Point pp, bool on)
  447. {
  448.     if (on) {
  449.     int code;
  450.     if (itemptr && itemptr->Enabled())
  451.         code= lvp->SetSelection(Rectangle(item, gPoint1));
  452.     else
  453.         code= lvp->SetSelection(gRect0);
  454.     lvp->DoOnItem(code, itemptr, pp);
  455.     }
  456. }
  457.  
  458. Command *CellSelector::TrackMouse(TrackPhase atp, Point, Point, Point np)
  459. {
  460.     bool outside= FALSE;
  461.     
  462.     item= lvp->PointToItem(np, &outside);
  463.     if (outside && lvp->TestFlag(eCVDontStuckToBorder))
  464.     itemptr= 0;
  465.     else
  466.     itemptr= lvp->GetItem(item.x, item.y);
  467.     
  468.     switch (atp) {
  469.     case eTrackRelease:
  470.     lvp->DoSelect2(lvp->GetSelection(), clickCount);
  471.     case eTrackExit:
  472.     return gNoChanges;
  473.     default:
  474.     break;
  475.     }
  476.     return this;
  477. }
  478.  
  479.